﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Update.Servers.LanZou
{
    /// <summary>
    /// 蓝奏云API封装
    /// </summary>
    public class LanZouApi : IDisposable
    {
        private HttpClient _httpClient;
        private readonly CookieContainer _cookieContainer;
        private Uri _baseUri;
        private string _versionPattern = @"update_(\d+\.\d+\.\d+)\.zip"; // 默认版本号提取模式
        private readonly int _maxRetries = 3; // 最大重试次数
        private readonly int _retryDelay = 1000; // 重试延迟(毫秒)
        private bool _disposed = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        public LanZouApi() : this(null)
        {
        }

        /// <summary>
        /// 带基础URL的构造函数
        /// </summary>
        /// <param name="baseUrl">蓝奏云基础URL</param>
        public LanZouApi(string baseUrl)
        {
            _cookieContainer = new CookieContainer();
            var handler = new HttpClientHandler
            {
                CookieContainer = _cookieContainer,
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
            };
            _httpClient = new HttpClient(handler);
            
            // 设置超时时间
            _httpClient.Timeout = TimeSpan.FromSeconds(30);

            // 设置默认请求头
            _httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36");
            _httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8");
            _httpClient.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
            _httpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
            _httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
            _httpClient.DefaultRequestHeaders.Add("Sec-Fetch-Dest", "document");
            _httpClient.DefaultRequestHeaders.Add("Sec-Fetch-Mode", "navigate");
            _httpClient.DefaultRequestHeaders.Add("Sec-Fetch-Site", "none");
            _httpClient.DefaultRequestHeaders.Add("Sec-Fetch-User", "?1");
            _httpClient.DefaultRequestHeaders.Add("Cache-Control", "max-age=0");

            // 如果提供了基础URL，设置它
            if (!string.IsNullOrEmpty(baseUrl))
            {
                SetBaseUrl(baseUrl);
            }
        }

        /// <summary>
        /// 设置API的基础URL
        /// </summary>
        /// <param name="baseUrl">蓝奏云基础URL</param>
        public void SetBaseUrl(string baseUrl)
        {
            if (!string.IsNullOrEmpty(baseUrl))
            {
                if (!baseUrl.StartsWith("http://") && !baseUrl.StartsWith("https://"))
                {
                    baseUrl = "https://" + baseUrl;
                }
                _baseUri = new Uri(baseUrl);
            }
        }

        /// <summary>
        /// 设置版本号提取正则表达式
        /// </summary>
        /// <param name="pattern">正则表达式，必须包含一个捕获组用于提取版本号</param>
        public void SetVersionPattern(string pattern)
        {
            if (!string.IsNullOrEmpty(pattern))
            {
                _versionPattern = pattern;
            }
        }

        /// <summary>
        /// 获取当前使用的域名
        /// </summary>
        /// <param name="shareUrl">分享链接(可选)</param>
        /// <returns>域名</returns>
        private string GetDomain(string shareUrl = null)
        {
            if (_baseUri != null)
            {
                return _baseUri.Host;
            }
            if (!string.IsNullOrEmpty(shareUrl))
            {
                return new Uri(shareUrl).Host;
            }
            return "wws.lanzoux.com"; // 默认域名
        }

        /// <summary>
        /// 文件信息类
        /// </summary>
        public class LanZouFile
        {
            /// <summary>
            /// 文件名
            /// </summary>
            public string FileName { get; set; }

            /// <summary>
            /// 文件大小
            /// </summary>
            public string FileSize { get; set; }

            /// <summary>
            /// 上传时间
            /// </summary>
            public string UploadTime { get; set; }

            /// <summary>
            /// 下载链接
            /// </summary>
            public string DownloadUrl { get; set; }

            /// <summary>
            /// 文件ID
            /// </summary>
            public string FileId { get; set; }
        }

        /// <summary>
        /// 动态参数类
        /// </summary>
        private class DynamicParams
        {
            public string t { get; set; }
            public string k { get; set; }
            public string fid { get; set; }
            public string uid { get; set; }
        }

        /// <summary>
        /// 从HTML中提取动态参数
        /// </summary>
        /// <param name="html">HTML内容</param>
        /// <returns>动态参数</returns>
        private DynamicParams ExtractDynamicParams(string html)
        {
            try
            {
                // 匹配参数定义部分
                var paramPattern = @"data\s*:\s*{\s*[^}]*'t'\s*:\s*(\w+)[^}]*'k'\s*:\s*(\w+)";
                var paramMatch = Regex.Match(html, paramPattern, RegexOptions.Singleline);

                if (!paramMatch.Success) return null;

                var tVar = paramMatch.Groups[1].Value;
                var kVar = paramMatch.Groups[2].Value;

                // 提取 t 值
                var tRegex = new Regex($@"var {tVar}\s*=\s*'([^']+)'");
                var tMatch = tRegex.Match(html);

                // 提取 k 值
                var kRegex = new Regex($@"var {kVar}\s*=\s*'([a-f0-9]{{32}})'");
                var kMatch = kRegex.Match(html);

                // 提取 fid 值
                var fidRegex = new Regex(@"'fid'\s*:\s*'?(\d+)'?");
                var fidMatch = fidRegex.Match(html);

                // 提取 uid 值
                var uidRegex = new Regex(@"'uid'\s*:\s*'?(\d+)'?");
                var uidMatch = uidRegex.Match(html);

                if (!tMatch.Success || !kMatch.Success || !fidMatch.Success || !uidMatch.Success)
                    return null;

                return new DynamicParams
                {
                    t = tMatch.Groups[1].Value,
                    k = kMatch.Groups[1].Value,
                    fid = fidMatch.Groups[1].Value,
                    uid = uidMatch.Groups[1].Value
                };
            }
            catch (Exception ex)
            {
                Console.WriteLine($"提取动态参数失败: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 使用重试机制执行HTTP请求
        /// </summary>
        /// <param name="action">HTTP请求操作</param>
        /// <returns>操作结果</returns>
        private async Task<T> RetryHttpRequestAsync<T>(Func<Task<T>> action)
        {
            int attempt = 0;
            Exception lastException = null;

            while (attempt < _maxRetries)
            {
                try
                {
                    // 如果不是第一次尝试，先等待
                    if (attempt > 0)
                    {
                        await Task.Delay(_retryDelay * attempt);
                        Console.WriteLine($"HTTP请求重试，第{attempt}次尝试");
                    }

                    return await action();
                }
                catch (Exception ex)
                {
                    attempt++;
                    lastException = ex;
                    Console.WriteLine($"HTTP请求失败 (尝试 {attempt}/{_maxRetries}): {ex.Message}");
                }
            }

            // 所有尝试都失败
            throw new Exception($"在{_maxRetries}次尝试后HTTP请求失败", lastException);
        }

        /// <summary>
        /// 获取分享文件夹中的文件列表，按上传时间排序
        /// </summary>
        /// <param name="shareUrl">分享链接</param>
        /// <param name="password">分享密码</param>
        /// <param name="descending">是否按降序排列（默认为true，最新的排在前面）</param>
        /// <returns>文件列表</returns>
        public async Task<List<LanZouFile>> GetFileListAsync(string shareUrl, string password, bool descending = true)
        {
            var files = new List<LanZouFile>();
            try
            {
                // 1. 请求分享页面
                var response = await _httpClient.GetAsync(shareUrl);

                Console.WriteLine($"正在请求URL: {shareUrl}");
                var responseContent = await response.Content.ReadAsStringAsync();
                Console.WriteLine($"响应内容: {responseContent.Substring(0, Math.Min(500, responseContent.Length))}...");
                response.EnsureSuccessStatusCode();
                var html = await response.Content.ReadAsStringAsync();

                // 2. 输入密码（如果需要）
                //if (html.Contains("请输入密码") && !string.IsNullOrEmpty(password)) {
                //    var formData = new FormUrlEncodedContent(new[] {
                //        new KeyValuePair<string, string>("pwd", password),
                //        new KeyValuePair<string, string>("action", "downprocess")
                //    });

                //    var passwordResponse = await _httpClient.PostAsync(shareUrl, formData);
                //    passwordResponse.EnsureSuccessStatusCode();

                //    // 重新获取页面内容
                //    response = await _httpClient.GetAsync(shareUrl);
                //    response.EnsureSuccessStatusCode();
                //    html = await response.Content.ReadAsStringAsync();
                //}

                // 3. 提取动态参数
                var dynamicParams = ExtractDynamicParams(html);
                if (dynamicParams == null)
                {
                    throw new Exception("无法提取页面参数");
                }

                // 4. 获取文件列表
                // 更新为用户提供的URL地址
                string domain = GetDomain(shareUrl);
                var fileListUrl = $"https://{domain}/filemoreajax.php";

                var fileListData = new FormUrlEncodedContent(new[] {
                    new KeyValuePair<string, string>("lx", "2"),
                    new KeyValuePair<string, string>("fid", dynamicParams.fid),
                    new KeyValuePair<string, string>("uid", dynamicParams.uid),
                    new KeyValuePair<string, string>("t", dynamicParams.t),
                    new KeyValuePair<string, string>("k", dynamicParams.k),
                    new KeyValuePair<string, string>("up", "1"),
                    new KeyValuePair<string, string>("pg", "1"),
                    new KeyValuePair<string, string>("rep", "0"),
                    // 如果存在密码，添加pwd参数
                    new KeyValuePair<string, string>("pwd", password ?? ""),
                    new KeyValuePair<string, string>("ls", "1")
                });

                var fileListResponse = await _httpClient.PostAsync(fileListUrl, fileListData);
                fileListResponse.EnsureSuccessStatusCode();
                var fileListJson = await fileListResponse.Content.ReadAsStringAsync();

                // 5. 解析文件列表
                dynamic fileListObj = JsonConvert.DeserializeObject(fileListJson);
                if (fileListObj.zt != 1)
                {
                    throw new Exception("获取文件列表失败: " + fileListObj.info);
                }

                foreach (var fileObj in fileListObj.text)
                {
                    string fileName = fileObj.name_all;
                    string fileId = fileObj.id;
                    string fileSize = fileObj.size;
                    string uploadTime = fileObj.time;

                    // 创建文件对象
                    var file = new LanZouFile
                    {
                        FileName = fileName,
                        FileSize = fileSize,
                        UploadTime = uploadTime,
                        FileId = fileId
                    };

                    files.Add(file);
                }

                // 6. 按上传时间排序
                if (descending)
                {
                    // 降序排列，最新的排在前面
                    files = files.OrderByDescending(f => ConvertLanZouTimeToDateTime(f.UploadTime)).ToList();
                }
                else
                {
                    // 升序排列，最早的排在前面
                    files = files.OrderBy(f => ConvertLanZouTimeToDateTime(f.UploadTime)).ToList();
                }

                return files;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取文件列表失败: {ex.Message}");
                return files;
            }
        }

        /// <summary>
        /// 将蓝奏云时间格式转换为DateTime
        /// </summary>
        /// <param name="lanZouTime">蓝奏云格式的时间字符串，如"2025-05-09"</param>
        /// <returns>DateTime对象</returns>
        private DateTime ConvertLanZouTimeToDateTime(string lanZouTime)
        {
            if (DateTime.TryParse(lanZouTime, out DateTime result))
            {
                return result;
            }
            return DateTime.MinValue; // 默认值，如果解析失败
        }

        /// <summary>
        /// 获取最新的文件
        /// </summary>
        /// <param name="shareUrl">分享链接</param>
        /// <param name="password">分享密码</param>
        /// <returns>最新的文件</returns>
        public async Task<LanZouFile> GetLatestFileAsync(string shareUrl, string password)
        {
            var files = await GetFileListAsync(shareUrl, password, true);
            return files.FirstOrDefault();
        }

        /// <summary>
        /// 获取更新日志
        /// </summary>
        /// <param name="fileId">文件ID</param>
        /// <returns>更新日志内容</returns>
        public async Task<string> GetChangelogAsync(string fileId)
        {
            try
            {
                string domain = GetDomain();
                var fileUrl = $"https://{domain}/{fileId}";

                var response = await _httpClient.GetAsync(fileUrl);
                response.EnsureSuccessStatusCode();
                var html = await response.Content.ReadAsStringAsync();

                // 提取更新日志
                var changelogMatch = Regex.Match(html, @"日志开始([\s\S]*?)日志结束");
                if (changelogMatch.Success)
                {
                    string changelog = changelogMatch.Groups[1].Value;

                    // 处理HTML转义字符
                    changelog = WebUtility.HtmlDecode(changelog);
                    
                    // 处理HTML标签
                    // 将<br>、<br/>、<br />等标签替换为换行符
                    changelog = Regex.Replace(changelog, @"<br\s*/?>\s*", "\r\n");
                    
                    // 处理其他可能的HTML标签（如果需要）
                    changelog = Regex.Replace(changelog, @"<[^>]+>", "");

                    return changelog.Trim();
                }

                return string.Empty;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取更新日志失败: {ex.Message}");
                return string.Empty;
            }
        }

        /// <summary>
        /// 获取文件下载链接
        /// </summary>
        /// <param name="fileId">文件ID</param>
        /// <returns>下载链接</returns>
        public async Task<string> GetFileDownloadUrlAsync(string fileId)
        {
            return await RetryHttpRequestAsync(async () =>
            {
                try
                {
                    // 使用新的直链提取器获取下载链接
                    var extractor = new LanZouDirectLinkExtractor();
                    string fileUrl = $"https://{GetDomain()}/{fileId}";
                    var fileInfo = await extractor.ExtractDirectLinkAsync(fileUrl);
                    
                    if (fileInfo != null && !string.IsNullOrEmpty(fileInfo.DownloadUrl))
                    {
                        return fileInfo.DownloadUrl;
                    }
                    
                    throw new Exception("无法获取文件下载链接");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"获取文件下载链接失败: {ex.Message}");
                    throw;
                }
            });
        }

        /// <summary>
        /// 获取所有版本信息
        /// </summary>
        /// <param name="shareUrl">分享链接</param>
        /// <param name="password">分享密码</param>
        /// <returns>版本列表，格式为版本号=>文件信息</returns>
        public async Task<Dictionary<string, LanZouFile>> GetVersionsAsync(string shareUrl, string password)
        {
            var versions = new Dictionary<string, LanZouFile>();
            try
            {
                var files = await GetFileListAsync(shareUrl, password);
                foreach (var file in files)
                {
                    // 提取版本号
                    var versionMatch = Regex.Match(file.FileName, _versionPattern);
                    if (versionMatch.Success && versionMatch.Groups.Count > 1)
                    {
                        string version = versionMatch.Groups[1].Value;
                        versions[version] = file;
                    }
                }

                return versions;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取版本信息失败: {ex.Message}");
                return versions;
            }
        }

        /// <summary>
        /// 获取最新版本
        /// </summary>
        /// <param name="shareUrl">分享链接</param>
        /// <param name="password">分享密码</param>
        /// <returns>最新版本号</returns>
        public async Task<string> GetLatestVersionAsync(string shareUrl, string password)
        {
            try
            {
                var versions = await GetVersionsAsync(shareUrl, password);
                if (versions.Count == 0)
                {
                    return null;
                }

                // 解析版本号并排序
                var versionsList = versions.Keys.ToList();
                versionsList.Sort((v1, v2) =>
                {
                    var v1Parts = v1.Split('.').Select(int.Parse).ToArray();
                    var v2Parts = v2.Split('.').Select(int.Parse).ToArray();

                    for (int i = 0; i < Math.Min(v1Parts.Length, v2Parts.Length); i++)
                    {
                        if (v1Parts[i] != v2Parts[i])
                        {
                            return v2Parts[i].CompareTo(v1Parts[i]); // 降序排列
                        }
                    }

                    return v2Parts.Length.CompareTo(v1Parts.Length);
                });

                return versionsList.FirstOrDefault();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取最新版本失败: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    // 释放托管资源
                    if (_httpClient != null)
                    {
                        _httpClient.Dispose();
                        _httpClient = null;
                    }
                }

                _disposed = true;
            }
        }

        ~LanZouApi()
        {
            Dispose(false);
        }
    }
}
